/**
  ******************************************************************************
  * Copyright © Beijing WIIP Co., Ltd. 2022-2024. All rights reserved.
  ******************************************************************************
  * @file: ws2812b.c
  * @brief: ws2812b全彩LED功能模块源文件
  *
  ******************************************************************************
  * @note: 调用底层库函数，封装为RBG的功能函数
  *
  *
  ******************************************************************************
  * Change Logs:
  * Date           Author       Notes
  * 2024-05-14     Edward       the first version
  *
  *
  ******************************************************************************
  */

#include "ws2812b.h"

RGB_Val_t RGB_Val;
/**
  * @brief  ws2812b硬件初始化
  * @param  None
  * @retval None
  */
void WS2812B_init(void)
{
    /* todo:添加PWM的初始化函数，如：HAL_TIM_PWM_Init(&htim1);*/
}

/**
  * @brief  rgb数据缓冲区中某一像素装载复位数据
  * @param  rgb 需要操作的RGB设备结构体
  * @param  num 数据缓冲区中操作数据的地址
  * @retval None
  */
static void loadResetData(ws2812b_t *rgb, uint8_t num)
{
    for (int j = 0; j < GRB_BITS; ++j)
    {
        rgb->DMABuffer[num][j] = 0;
    }
}

/**
  * @brief  rgb数据缓冲区中某一像素装载颜色数据
  * @param  rgb 需要操作的RGB设备结构体
  * @param  num 数据缓冲区中操作数据的地址
  * @param  color 装载的颜色数据
  * @retval None
  */
static void loadColorData(ws2812b_t *rgb, uint8_t num, uint32_t color)
{
    for (int j = 0; j < GRB_BITS; ++j)
    {
        rgb->DMABuffer[num][j] = ((color << j) & 0x800000)? WS_HIGH: WS_LOW;
    }
}

/**
  * @brief  通过PWM+DMA的方式将rgb数据缓冲区中的数据进行发送
  * @param  rgb 需要操作的RGB设备结构体
  * @retval None
  */
static void WS2812B_sendDataBuffer(ws2812b_t *rgb)
{
    uint8_t tmp;

    tmp = rgb->readyLength + rgb->pixelLength + rgb->resetLength;
    /* todo:添加PWM发送函数 如：HAL_TIM_PWM_Start_DMA(&htim1, TIM_CHANNEL_2, (uint32_t*)rgb->DMABuffer, tmp * GRB_BITS);*/
}

/**
  * @brief  将r、g、b数据拼装成规定格式数据
  * @param  r 需要操作的RGB设备结构体
  * @param  g
  * @param  b
  * @retval rgb颜色拼装完成后的结构体
  */
RGB_Val_t WS2812B_pieceRGB(uint8_t r, uint8_t g, uint8_t b)
{
    RGB_Val_t RGB_Val;

    RGB_Val.single.r = r;
    RGB_Val.single.g = g;
    RGB_Val.single.b = b;

    return RGB_Val;
}

/**
  * @brief  ws2812b所有像素显示同一个颜色
  * @param  rgb 需要操作的RGB设备结构体
  * @param  RGB_Val 需要显示的颜色结构体
  * @retval None
  */
void WS2812B_showAllSameColor(ws2812b_t *rgb, RGB_Val_t RGB_Val)
{
    int i;
    RGB_Val_t tmpRGB_Val;

    tmpRGB_Val.single.r = RGB_Val.single.r * rgb->intensity / 100;
    tmpRGB_Val.single.g = RGB_Val.single.g * rgb->intensity / 100;
    tmpRGB_Val.single.b = RGB_Val.single.b * rgb->intensity / 100;

    for (i = 0; i < rgb->readyLength; ++i)
    {
        loadResetData(rgb, i);
    }
    for (i = 0; i < rgb->pixelLength; ++i)
    {
        loadColorData(rgb, i + rgb->readyLength, tmpRGB_Val.combined);
    }
    for (i = 0; i < rgb->resetLength; ++i)
    {
        loadResetData(rgb, i + rgb->readyLength + rgb->pixelLength);
    }
    WS2812B_sendDataBuffer(rgb);
}

/**
  * @brief  ws2812b一段像素显示某一颜色
  * @param  rgb 需要操作的RGB设备结构体
  * @param  RGB_Val 需要显示的颜色结构体
  * @param  head 显示一段颜色的头位置
  * @param  length 显示一段颜色的像素长度
  * @retval None
  */
void WS2812B_showOneFlowLight(ws2812b_t *rgb, RGB_Val_t RGB_Val, uint8_t head, uint8_t length)
{
    int i;

    for (i = 0; i < rgb->readyLength; ++i)
    {
        loadResetData(rgb, i);
    }
    for (i = 0; i < rgb->pixelLength; ++i)
    {
        if(i >= head && i < (head + length))
            loadColorData(rgb, i + rgb->readyLength, RGB_Val.combined);
        else
            loadColorData(rgb, i + rgb->readyLength, 0);
    }
    for (i = 0; i < rgb->resetLength; ++i)
    {
        loadResetData(rgb, i + rgb->readyLength + rgb->pixelLength);
    }
    WS2812B_sendDataBuffer(rgb);
}

/**
  * @brief  ws2812b两段像素显示某一颜色 【未完成 待调试】
  * @retval None
  */
void WS2812B_showTwoFlowLight(ws2812b_t *rgb, RGB_Val_t RGB_Val1, uint8_t head1, uint8_t length1,
        RGB_Val_t RGB_Val2, uint8_t head2, uint8_t length2)
{
    int i;

    for (i = 0; i < rgb->readyLength; ++i)
    {
        loadResetData(rgb, i);
    }
    for (i = 0; i < rgb->pixelLength; ++i)
    {
        if(i >= head1 && i < (head1 + length1))
            loadColorData(rgb, i + rgb->readyLength, RGB_Val1.combined);
        else
            loadColorData(rgb, i + rgb->readyLength, 0);

        if(i >= head2 && i < (head2 + length2))
            loadColorData(rgb, i + rgb->readyLength, RGB_Val2.combined);
        else
            loadColorData(rgb, i + rgb->readyLength, 0);
    }
    for (i = 0; i < rgb->resetLength; ++i)
    {
        loadResetData(rgb, i + rgb->readyLength + rgb->pixelLength);
    }
    WS2812B_sendDataBuffer(rgb);
}

/**
  * @brief  ws2812b全面像素显示彩虹灯
  * @param  rgb 需要操作的RGB设备结构体
  * @retval None
  */
void WS2812B_showRainbowFlow(ws2812b_t *rgb)
{
    int i;
    static RGB_Val_t tmpRGB_Val = {.combined = 0x000000FF};

    for (i = 0; i < rgb->readyLength; ++i)
    {
        loadResetData(rgb, i);
    }
    for (i = 0; i < rgb->pixelLength; ++i)
    {
        loadColorData(rgb, i + rgb->readyLength, tmpRGB_Val.combined);
        tmpRGB_Val.combined = tmpRGB_Val.combined << 1;
        if(tmpRGB_Val.combined & 0x1000000)
        {
            tmpRGB_Val.combined |= 0x000001;
        }
    }
    for (i = 0; i < rgb->resetLength; ++i)
    {
        loadResetData(rgb, i + rgb->readyLength + rgb->pixelLength);
    }
    WS2812B_sendDataBuffer(rgb);
}
